package com.leige.tesseractocrlibrary

import android.content.Context
import android.graphics.Bitmap
import android.util.Log
import com.googlecode.tesseract.android.TessBaseAPI
import java.io.File
import java.io.InputStream
import java.io.OutputStream


/**
 * Created by liulei
 * 2019/12/21 18:55
 * TesseractOCR api
 */
internal class TesseractOCR() {

    private var mTess: TessBaseAPI? = null

    fun getOCRResult(bitmap: Bitmap?): String {
        mTess?.setImage(bitmap)
        val str = mTess?.getHOCRText(0) ?: ""
        Log.e("tessOcr", "getHOCRText str = $str")
        return mTess?.utF8Text ?: ""
    }

    private var appContext: Context? = null

    constructor(context: Context) : this() {
        appContext = context.applicationContext
    }

    fun onDestroy() {
        mTess?.end()
    }

    fun initApi() {
        try {
            init()
        } catch (ex: Throwable) {
            Log.e("initOcr", "ex = ${ex.message}")
            ex.printStackTrace()
        }
    }

    object TrainDataConfig {
        //const val traineddataPath = "assets://chi_sim_vert.traineddata"
        var traineddatafileName = "chi_sim.traineddata"
        //const val traineddataPath = "/storage/emulated/0/Download/chi_sim_vert.traineddata"
        var traineddataPath = "/storage/emulated/0/Download/chi_sim.traineddata"
        var trainedLang = "chi_sim"
    }

    fun initDataConfig(traineddatafileName: String, traineddataPath: String, trainedLang: String) {
        if (traineddatafileName.isEmpty() || traineddataPath.isEmpty() || trainedLang.isEmpty()) {
            throw IllegalArgumentException("traineddatafileName or traineddataPath or trainedLang can't be null or empty.")
        }
        TrainDataConfig.traineddatafileName = traineddatafileName
        TrainDataConfig.traineddataPath = traineddataPath
        TrainDataConfig.trainedLang = trainedLang
    }

    private fun init() {
        Log.e("initOcr", "start init()")
        mTess = TessBaseAPI(TessBaseAPI.ProgressNotifier {
            Log.e("ocrProgress", "percent = " + it.percent)
        })
        mTess?.setDebug(true)
        if (appContext == null) {
            Log.e("initOcr", "return init() appContext = null")
            return
        }

        val ctx = appContext!!
        // 拷贝数据到私有路径中
        val path = TrainDataConfig.traineddataPath
        if (path.startsWith("/"))
            copyToMemory(ctx, File(path), TrainDataConfig.trainedLang)
        else if (path.startsWith("assets")) {
            copyToMemory(ctx, path, TrainDataConfig.trainedLang)
        }
        val ret = mTess?.init(
            "${ctx.filesDir.path}/tesseract/",
            TrainDataConfig.trainedLang,
            TessBaseAPI.OEM_DEFAULT
        )
        Log.e("initOcr", "ret = $ret")
    }

    fun setOnlySupportDigital() {
        //目前LSTM是无法支持白名单的
        mTess?.setVariable(TessBaseAPI.VAR_CHAR_WHITELIST, "1234567890xX")
    }

    private fun copyToMemory(ctx: Context, file: File, language: String) {
        val fis = file.inputStream()
        val destDir = File(ctx.filesDir, "/tesseract/tessdata")
        if (!destDir.exists()) {
            destDir.mkdirs()
        }
        val destFile = File(destDir, "${language}.traineddata")
        val fos = destFile.outputStream()
        copyFile(fis, fos)
    }

    private fun copyToMemory(ctx: Context, assetPath: String, language: String) {
        val fis = ctx.assets.open(assetPath)
        val destDir = File(ctx.filesDir, "/tesseract/tessdata")
        if (!destDir.exists()) {
            destDir.mkdirs()
        }
        val destFile = File(destDir, "${language}.traineddata")
        val fos = destFile.outputStream()
        copyFile(fis, fos)
    }

    private fun copyFile(fis: InputStream, fos: OutputStream) {
        val buffer = ByteArray(1024)
        var len: Int
        while (true) {
            len = fis.read(buffer)
            if (len != -1) {
                fos.write(buffer, 0, len)
                continue
            }
            break
        }
        fos.flush()
        fos.close()
        fis.close()
    }

}